package la.iok.hzsvn.lewin.movie.operation.service;

import la.iok.hzsvn.lewin.movie.core.exception.ErrorCode;
import la.iok.hzsvn.lewin.movie.core.model.FinancialAccountVo;
import la.iok.hzsvn.lewin.movie.operation.entity.FinancialAccount;
import la.iok.hzsvn.lewin.movie.operation.entity.LuckyMoney;
import la.iok.hzsvn.lewin.movie.operation.mapper.FinancialAccountMapper;
import la.iok.hzsvn.lewin.mybatis.service.BaseServiceImpl;
import la.iok.hzsvn.share.annotations.NotNull;
import la.iok.hzsvn.share.annotations.NotNullElement;
import la.iok.hzsvn.share.annotations.Nullable;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Calendar;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class FinancialAccountServiceImpl extends BaseServiceImpl<FinancialAccount, FinancialAccountMapper,Long> implements FinancialAccountService {
    private final LuckyMoneyService luckyMoneyService;
    public FinancialAccountServiceImpl(FinancialAccountMapper mapper,
                                       LuckyMoneyService luckyMoneyService) {
        super(mapper);
        this.luckyMoneyService = luckyMoneyService;
    }

    @Transactional
    @Override
    public void charge(@Nullable Long roomId, @Nullable Integer amount) {
        ErrorCode.PROPERTY_CHECK_ERROR.assertNotNull(amount,"金额","金额不能为空");
        ErrorCode.PROPERTY_CHECK_ERROR.assertNotNull(roomId,"房间id","房间id不能为空");
        ErrorCode.PROPERTY_CHECK_ERROR.assertTrue(amount != 0,"金额","金额不能为0");
        ErrorCode.PROPERTY_CHECK_ERROR.assertTrue(roomId > 0,"房间id","房间id必须大于0");
        FinancialAccount account = select("roomId", roomId);
        if(account == null){
            account = new FinancialAccount();
            account.setBalance(amount);
            account.setRoomId(roomId);
            insertSelective(account);
            return;
        }
        int c = mapper.charge(account.getId(),account.getVersion(),amount);
        if(c != 1){
            //重试一次。可能被其他人刚刚并发修改了数据
            account = select("roomId", roomId);
            ErrorCode.FINANCIAL_CHANGE_ERROR.assertNotNull(account);
            c = mapper.charge(account.getId(),account.getVersion(),amount);
            ErrorCode.FINANCIAL_CHANGE_ERROR.assertEqual(1,c);
        }
    }

    @Override
    public int cost(@Nullable Long roomId, @Nullable Integer amount, @Nullable Long version) {
        if(roomId == null || amount == null || version == null){
            return 0;
        }
        return mapper.cost(roomId,amount,version);
    }

    @NotNull
    @NotNullElement
    @Override
    public List<FinancialAccountVo> accounts(@Nullable Collection<Long> roomIds) {
        List<FinancialAccount> list = listInProperty("roomId",roomIds);
        List<LuckyMoney> lucky = luckyMoneyService.currentReturnMoney(roomIds);
        return list.stream().map(item->po2vo(item,lucky)).collect(Collectors.toList());
    }

    private FinancialAccountVo po2vo(FinancialAccount item, List<LuckyMoney> lucky){
        if(item == null){
            return null;
        }
        FinancialAccountVo vo = new FinancialAccountVo();
        BeanUtils.copyProperties(item,vo);
        if(lucky != null){
            lucky.stream().filter(l -> Objects.equals(item.getRoomId(), l.getRoomId())).findFirst()
                    .ifPresent(luckyMoney -> vo.setLuckyMoney(luckyMoney.getAmount()));
        }
        return vo;
    }

    @Nullable
    @Override
    public FinancialAccount takeOneForReturn(@Nullable @NotNullElement Collection<Long> excludes, @NotNull @NotNullElement Collection<Long> supportReturnMoneyRoomIds) {
        Calendar c = Calendar.getInstance();
        int m = c.get(Calendar.MONTH)+1;
        int cnt = 0;
        FinancialAccount account;
        do{
            account = mapper.takeOneForReturn(m,excludes,supportReturnMoneyRoomIds);
            if(account == null){
                //没有记录了
                return null;
            }
            cnt = mapper.updateReturnMonth(account.getId(),account.getVersion(),m,account.getReturnMonth());
            if(cnt == 1){
                //修改成功,同时修改对象的属性
                account.setVersion(account.getVersion()+1);
                account.setReturnMonthBack(account.getReturnMonth());
                account.setReturnMonth(m);
            }
        }while (cnt != 1);
        return account;
    }

    @Override
    public List<FinancialAccount> takeForPreview(Collection<Long> excludes, Collection<Long> supportReturnMoneyRoomIds) {
        Calendar c = Calendar.getInstance();
        int m = c.get(Calendar.MONTH)+2;   //计算当月的反利数据应该是下月执行
        return mapper.takeForPreview(m, excludes,supportReturnMoneyRoomIds);
    }

    @Override
    public int returnMonthBack(FinancialAccount account) {
        if(account == null){
            return 0;
        }
        return mapper.updateReturnMonth(account.getId(),account.getVersion(),account.getReturnMonthBack(),-1);
    }

    @Override
    public FinancialAccount account(Long roomId) {
        if(roomId == null){
            return null;
        }
        FinancialAccount account = select("roomId",roomId);
        if(account == null){
            account = new FinancialAccount();
            account.setRoomId(roomId);
            insertSelective(account);
            return select("roomId",roomId);
        }else{
            return account;
        }
    }
}
